// 这是一个 Go 语言库，用于在所有支持的 Go 操作系统上启用直接 IO。
//
// 直接 IO 是指在不通过操作系统缓冲的情况下直接与磁盘进行 IO 操作。
// 当你需要读写大量数据而不希望填满操作系统缓存时，这非常有用。
//
// 使用 turbocopy.OpenFile 代替 os.OpenFile
//
//	in, err := turbocopy.OpenFile(file, os.O_RDONLY, 0666)
//
// 在读写数据块时，确保使用 turbocopy.BlockSize 大小的块，并使用 turbocopy.AlignedBlock 分配内存
//
//		block := turbocopy.AlignedBlock(BlockSize)
//	        _, err := io.ReadFull(in, block)
package turbocopy

import (
	"log"
	"unsafe"
)

// alignment 返回内存中块相对于 AlignSize 的对齐情况
//
// 不能检查大小为零的块的对齐情况，因为 &block[0] 无效
func alignment(block []byte, AlignSize int) int {
	return int(uintptr(unsafe.Pointer(&block[0])) & uintptr(AlignSize-1))
}

// IsAligned 检查传入的字节切片是否已对齐
func IsAligned(block []byte) bool {
	return alignment(block, AlignSize) == 0
}

// AlignedBlock 返回大小为 BlockSize 的 []byte，在内存中按 AlignSize 的倍数对齐（必须是 2 的幂）
func AlignedBlock(BlockSize int) []byte {
	block := make([]byte, BlockSize+AlignSize)
	if AlignSize == 0 {
		return block
	}
	a := alignment(block, AlignSize)
	offset := 0
	if a != 0 {
		offset = AlignSize - a
	}
	block = block[offset : offset+BlockSize]
	// 不能检查大小为零的块的对齐情况
	if BlockSize != 0 {
		if !IsAligned(block) {
			log.Fatal("无法对齐块")
		}
	}
	return block
}
